/*
 * MessageClient.h
 *
 *  Created on: 2010-8-11
 *      Author: stargui
 */

#ifndef MESSAGECLIENT_H_
#define MESSAGECLIENT_H_

#include <errno.h>
#include <fcntl.h>
#include <map>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include "CSocketUtils.h"
#include "CSelectUtils.h"

namespace Common
{

enum
{
	EVENT_SERVER_REGISTER = 0, ///< 消息服务器注册消息
	EVENT_SERVER_UNREGISTER = 1,///< 消息服务器注消消息
	EVENT_SERVER_HEARTBEAT = 2, ///< 消息服务器心跳包
	EVENT_SERVER_WATCHDOG_CLEAR, ///< 清看门狗
	EVENT_SERVER_WATCHDOG_ENABLE, ///< 使能硬件看门狗
	EVENT_SERVER_WATCHDOG_DISABLE, ///< 禁止硬件看门狗
	EVENT_SERVER_WATCHDOG_REGISTER, ///< 注册软件看门狗
	EVENT_SERVER_WATCHDOG_UNREGISTER, ///< 注消软件看门狗
	EVENT_SERVER_WATCHDOG_RESTART, ///< 系统软重启
	EVENT_SERVER_WATCHDOG_POWERDOWN, ///< 系统关机
	EVENT_SERVER_SET_DEBUGLEVEL,///< 设置模块调试等级
	EVENT_SERVER_EVENTMASK = 0xFFFF,
	MAX_MESSAGE_SIZE = 1400,
	RESPONSE_FLAG = 0x8000,
	SOCKET_MAGIC = 0xABCD,
};

/** @struct SMessageHead
 @brief 消息头结构定义
 */
typedef struct
{
	int32_t source; ///< 数据源标示
	int32_t session; ///< session ID
	uint16_t magic; ///< magic number
	uint16_t event; ///< 事件类型
	uint32_t length :23; ///< 消息数据长度
	uint32_t response :1; ///< 返回请求标志，本消息是否需要返回。
	uint32_t S :1;
	uint32_t E :1;
	uint32_t reserve :6;
	char body[0]; ///< 消息数据
} SMessageHead;

/** @struct SMsgRegister
 @brief 消息注册结构体
 */
typedef struct
{
	uint16_t event; ///< 注册事件
	uint16_t timeout; ///< 超时时间
} SMsgRegister;

/** @struct SWatchdogMsg
 @brief 看门狗消息结构。包括清狗，注册，注销消息， 超时，启停进程时使用
 */
#define WATCHDOG_NAME_LEN 32
typedef struct
{
	char name[WATCHDOG_NAME_LEN]; ///< 看门狗名称，命名规则，进程名 ＋ "." ＋ 线程区分ID
	unsigned int interval; ///< 软件看门狗超时时间。
} SWatchdogMsg;

/** @struct SMsgSetDebugLevel EVENT_DEBUG_SETDEBUGLEVEL
 @brief 设置调试等级
 */
typedef struct
{
	unsigned short module;
	unsigned short level;
	unsigned short output;
	unsigned short reserve;
} SMsgSetDebugLevel;

/** @class CMessageClient
 @brief 消息处理客户端类
 */
class CMessageClient
{
private:

	bool OnDisconnected();

	void AliveTickCount(void);

	char * PackageMessage(SMessageHead *header, size_t totalLen);

	char * SerializeMessage();

	bool RecieveMessage(int handle);

public:

	/**
	 * @brief 构造函数
	 * @param aliveTime  心跳时间，超时将认为连接断开。
	 */
	CMessageClient(int aliveTime = 20);

	virtual ~CMessageClient();

public:
	/**
	 * @brief 创建消息传递Socket
	 * @param ip 	要连接的服务地址
	 * @param port  端口
	 * @return 成功返回true，失败 false
	 */
	bool CreateSocket(const char *ip, unsigned short port = 17777);

	/**
	 * @brief 事件发送函数。
	 * @param sessionId 消息目的 session
	 * @param event    事件类型。
	 * @param response 是否要求回复
	 * @param data     数据
	 * @param length   数据长度
	 * @param sourceid 源消息区分ID
	 * @return 成功true  失败false
	 */
	bool SendMessage(int sessionId, int event, int response, const char *data, int length, int sourceId);

	/**
	 * @brief 返回信息发送函数。
	 * @param head 接收的信息头。
	 * @param data 返回信息数据
	 * @param length 返回信息数据长度。
	 * @return 成功true  失败false
	 */
	bool ResponseMessage(SMessageHead *head, const char *data, int length);

	/**
	 * @brief 事件注册函数。
	 * @param event  事件类型
	 * @param handle 事件处理函数
	 * @return 成功true  失败false
	 */
	bool EventRegister(int event, boost::function<void(const char *, int)> handle);

	/**
	 * @brief 事件注销函数。
	 * @param event 要注销的事件。
	 * @return 成功true  失败false
	 */
	bool EventUnRegister(int event);

	/**
	 * @brief 事件等待函数，会抛出连接和有数据到达信号。
	 * @param timeout 等待超时时间
	 * @return 成功返回true， 失败 false
	 */
	bool WaitForEvent(int timeout = 10);

	/**
	 * @brief 事件等待函数，会抛出连接和有数据到达信号。
	 * @param timeout 等待超时时间
	 * @param remainder 超时剩余时间
	 * @return 成功返回true， 失败 false
	 */
	bool WaitForEvent(int &remainder, int timeout);

	/**
	 * @brief 获取MessageClinet句柄
	 * @return 成功返回MessageClinet句柄， 失败返回-1；
	 */
	int GetClientHandle(void);

private:

	int m_Socket;

	time_t m_TimeTick;

	char *_buffer;

	std::string _recvBuffer;

	std::map<int32_t, std::string> messages;

	unsigned int m_AliveTickCnt, m_AliveTime;

	std::map<unsigned short, boost::function<void(const char *, int)> > m_Handle;
};

}

#endif /* MESSAGECLIENT_H_ */
